#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

#define SOCKET int
#define MAX_LINK_NUM_INT 10
#define PORT (19527)
#define MAX_EVENTS 10
#define MAXLINE 10240

int main(int argc, char **argv)
{
    int ret;

    if( ( ret = server_main() ) < 0 )
    {
        printf("server_main err! ret = [%d]\n", ret );
        return -1;
    }

    return 0;
}

int server_main()
{
    struct epoll_event ev, events[MAX_EVENTS];
    int listen_sock, conn_sock, nfds, epollfd;
    int ret, n;
    struct sockaddr local;
    int addrlen = 1;


    memset( &local, 0x00, sizeof(local) );

    /* Set up listening socket, 'listen_sock' (socket(), bind(), listen()) */
    if( (ret = server_init( &listen_sock, PORT )) < 0)
    {
        printf("server_init err! ret = [%d]", ret );
        return -1;
    }
    printf("server_init success! listen_sock = [%d]\n", listen_sock );

    ret = thread_pool_init(&pool, MAX_THREAD);
    if (ret < 0)
    {
        printf("[%s][%d] Create thread pool failed!\n", __FILE__, __LINE__);
        return -1;
    }

    epollfd = epoll_create(10);//size用来告诉内核这个监听的数目一共有多大 自从Linux 2.6.8开始，size参数被忽略，但是依然要大于0
    if (epollfd == -1)
    {
        perror("epoll_create");
        exit(EXIT_FAILURE);
    }

    ev.events = EPOLLIN;
    ev.data.fd = listen_sock;
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1)
    {
        perror("epoll_ctl: listen_sock");
        exit(EXIT_FAILURE);
    }

    while(1)
    {
        nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
        if (nfds == -1)
        {
            perror("epoll_pwait");
            exit(EXIT_FAILURE);
        }

        for (n = 0; n < nfds; ++n)
        {
            if (events[n].data.fd == listen_sock)
            {
                conn_sock = accept(listen_sock, (struct sockaddr *) &local, &addrlen);
                if (conn_sock == -1)
                {
                    perror("accept");
                }
                setnonblocking(conn_sock);
                ev.events = EPOLLIN | EPOLLET;
                ev.data.fd = conn_sock;
                if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1)
                {
                    perror("epoll_ctl: conn_sock");
                }
            }
            else
            {
                thread_pool_add_worker(pool, do_use_fd, (void *) & (events[n].data.fd));
                ev.events = EPOLLIN | EPOLLET;
                ev.data.fd = events[n].data.fd;
                if (epoll_ctl(epollfd, EPOLL_CTL_DEL, listen_sock, &ev) == -1)
                {
                    perror("epoll_ctl:");
                }
            }
        }
    }
}
int server_init( SOCKET *server_sockfd, const int port_int )
{
    struct sockaddr_in server_addr;
    int val = 1;

    // socket
    if( (*server_sockfd = socket( AF_INET, SOCK_STREAM, 0 )) == -1 )
    {
        printf( "Error: create socket! (error code: %d - %s)\n", errno, strerror(errno) );
        return -1;
    }

    // addr
    setsockopt(*server_sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof (val));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons( port_int );
    server_addr.sin_addr.s_addr = INADDR_ANY;
    bzero( &(server_addr.sin_zero), 8 );

    // bind
    if( bind( *server_sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1 )
    {
        printf( "Error: bind! (error code: %d - %s)\n", errno, strerror(errno) );
        return -1;
    }

    // listen
    if( listen( *server_sockfd, MAX_LINK_NUM_INT ) == -1 )
    {
        printf("Error: listen! (error code:%d - %s)\n", errno, strerror(errno) );
        return -1;
    }

    return 0;
}

int setnonblocking(int sockfd)
{
    if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0) | O_NONBLOCK) == -1)
    {
        return -1;
    }
    return 0;
}
void *do_use_fd(void *connfd)
{
    printf("do_use_fd()\n");
    int nread;
    int rfd = *(int *)(connfd)
              char buf[MAXLINE];
    memset(buf, 0x00, MAXLINE);
    nread = read(rfd, buf, MAXLINE);//读取客户端socket流
    if (nread == 0)
    {
        printf("client close the connection\n");
        close(rfd);
        return -1;
    }
    if (nread < 0)
    {
        perror("read error");
        close(rfd);
        return -1;
    }
    /*add your deal begin*/
    printf("recv dta = [%s]\n", buf);
    write(rfd, buf, nread);//响应客户端
    /*add your deal end*/

    close(rfd);
    return 0;
}

